/*Vladimir Sarkisyan 312636962*/
package main;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Notation;
import org.w3c.dom.NamedNodeMap;
//import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import GUI.GUIview;

public class XMLReader {
	
	private static File file;
	private static DocumentBuilderFactory dbf;
	private static DocumentBuilder db;
	private static Document doc;
	private static String path;
	private static boolean fileOpen = false;
	private static Node currentNode = null,  rootNode = null;
	private static int count = 0;
	private static int numButtons = 0;
	public static XMLReader instance = new XMLReader();
	
	
	
	  public boolean isFileOpen() {
		return fileOpen;
	}



	public static void startRead(String path) throws Exception{
	
	  try {
		 //initialize the count to 0
		  count = 0;
		  //file = new File(path);
		  dbf = DocumentBuilderFactory.newInstance();
		  dbf.setNamespaceAware(true);
		  dbf.setValidating(true);
	
		  
		  db = dbf.newDocumentBuilder();
		  
	
		  //set the error handler
		  db.setErrorHandler(new org.xml.sax.ErrorHandler() {
		        //Ignore the fatal errors
	    	  
	        public void fatalError(SAXParseException exception)throws SAXException { 
	        	
	        	//System.out.println("in fatal error");
	        	GUIview.instance.updateComments("The open of the file failed");
	        	
	        }
	        //Validation errors 
	        public void error(SAXParseException e)throws SAXParseException {
	          //System.out.println("in  error");
	          //System.out.println("Error at " +e.getLineNumber() + " line.");
	          //System.out.println(e.getMessage());
	          GUIview.instance.updateComments("The DTD is incompatible");
	          //System.exit(0);
	        }
	        //Show warnings
	        public void warning(SAXParseException err)throws SAXParseException{
	           //System.out.println("in  warning");
	           //System.out.println(err.getMessage());
	          //System.exit(0);
	        }
	      });
		  
	  //validateDTD(path);
	  
	  //file = new File(path);
	  //System.out.println("temp1");
	  
	  doc = db.parse(path);
	  //System.out.println("temp2");
	  //get the DocumentType
	  DocumentType documentType = doc.getDoctype();
	  
	  //if there is not a documentType
	  if(documentType==null){
		  //System.out.println("no document");
		  //update in the comments
		  GUIview.instance.updateComments("No definition of DTD file");
	  }
	   //if it is not null
	  else{
		 // System.out.println("PublicId " + documentType.getPublicId());
		  //System.out.println("SystemId " + documentType.getSystemId());
		  if(documentType.getPublicId() == null){
			  
			  }
		  //should be 
		  if(documentType.getSystemId()== null){
			  GUIview.instance.updateComments("No definition of DTD file");
		  }
		  
		  if(documentType.getSystemId()!= null){
			  //GUIview.instance.updateComments("No definition of DTD file");
		  }		  
		  		  
	  }
	  //end of the else
	  
	  doc.getDocumentElement().normalize();
	  String root =  doc.getDocumentElement().getNodeName();
	  //System.out.println("Root element " + root);	
	  
	  //update that the file is open and the number of buttons
	  fileOpen = true;
	  numButtons = 1;
	  
	  //update the first node (the root) and the CurrentPath
	  //GUIview.instance.
	  GUIview.instance.updateButton(root, 0, true);
	  GUIview.instance.updateCurrentPath("/" + root);
	  
	  //now it is the root
	  currentNode = doc.getDocumentElement();
	  rootNode = currentNode;
	  //System.out.println("rootNode - " + currentNode.getNodeName());
	  
	  //update the value/name text
	  //GUIview.instance.setNameValueText(currentNode.getNodeName());
	  //get his childrens
	  readChildrens(currentNode);
	  	  
	  } 
	  /*
	  catch (ParserConfigurationException e) {
		  	System.out.println("in a");
	        System.out.println(e.toString()); 	
	  } catch (SAXException e) {
		  	System.out.println("in b");
	       System.out.println(e.toString()); 	
	  } catch (IOException e) {
		  System.out.println("in c");
	        System.out.println(e.toString()); 	
	   }*/
	  
	  catch (Exception e) {
	    e.printStackTrace();
	  }
	  
	 }
	  //end of start read
	  
	  
	/*
	 * The function get a node and find his children in the xml doc    
	 */
	public static void readChildrens(Node node){
	  
		  NodeList nodeLst = node.getChildNodes();
		  ArrayList<String> nodesList  = new ArrayList<String>();
		  
		  //System.out.println("in readChildrens");
		  //now it is the node that was chosen
		  currentNode = node;
		  
		  //System.out.println("currentNode: " + currentNode.getNodeName());
		  //empty the Attributes list
		  GUIview.instance.deleteAttributesList();
		  //check the Attributes
		  if(currentNode.hasAttributes()){
			  //get the atributes
			  //System.out.println("in the if currentNode.hasAttributes()");
			  NamedNodeMap namedNodeMap = currentNode.getAttributes();
			  for(int i=0; i<namedNodeMap.getLength(); i++){
				  Node attNode = namedNodeMap.item(i);
				 // System.out.println("attNode: " + attNode.getNodeName());
				  attNode.getNodeValue();
				  //System.out.println("attNode.getNodeValue: " + attNode.getNodeValue()); 
				  //add the attribute and his value to the attribute list 
				  GUIview.instance.addToAttributesList(attNode.getNodeName() + " = " + attNode.getNodeValue());
			  }
		  }
		  
		  //set the Name/Value Text
		  NodeList tempList =  currentNode.getChildNodes();
		  //in case there is a text
		  if(tempList.getLength() == 1){
			  GUIview.instance.setNameValueText(currentNode.getNodeName() + " = " + currentNode.getTextContent());
		  }
		  // in case there is not text
		  else{
			  GUIview.instance.setNameValueText(currentNode.getNodeName());
		  }
		  
		  
		  //System.out.println("nodeLst: " + nodeLst.getLength());
		  //empty the list
		  GUIview.instance.deleteElamentsList();
		  //add the new elements to the list
		  //System.out.println("--------------------------------Read The Nodes---------------------------------------");
		  for (int s = 0; s < nodeLst.getLength(); s++) {
			  
			  Node fstNode = nodeLst.item(s);
			  //check if it is element
			  if (fstNode.getNodeType() == Node.ELEMENT_NODE){
				  //System.out.println("Name: " + fstNode.getNodeName()); 
				  //System.out.println("TextContent: " + fstNode.getTextContent());
				  //add to the list
				  
				  //System.out.println("hasChileds: " + fstNode.hasChildNodes());

				  nodesList.add(fstNode.getNodeName());
			  }
		  }	//end for	
		  
		  //order the list, that will be with number if has to be
		  orderList(nodesList);
		  //System.out.println("after orderList");
		  
		  
		  
		  
		  //--------------add the elements with the values to the list in the GUI----------
		  int i = 0;
		  for (int s = 0; s < nodeLst.getLength(); s++) {
			  
			  Node fstNode = nodeLst.item(s);
			  //check if it is element
			  if (fstNode.getNodeType() == Node.ELEMENT_NODE){
				  //System.out.println("Name: " + nodesList.get(i)); 
				  //System.out.println("Name: " + fstNode.getNodeName());
			      //String val = fstNode.getTextContent();
				  //System.out.println("val: " + val);				  
				  /*if (fstNode.getNodeType() == Element.TEXT_NODE){
					  System.out.println("is a CDATA_SECTION_NODE");
;					  
				  }
				   */
				  
				  tempList =  fstNode.getChildNodes();
				  //check if there is text data
				  if(tempList.getLength() == 1){
					  //if there is a text content
					  if(fstNode.getTextContent() != null){
						  //System.out.println("TextContent: " + fstNode.getTextContent());
						//update the list of elements in the GUI
						  GUIview.instance.addToElemtList(nodesList.get(i) + " = " + fstNode.getTextContent());
					  }
					  else{
						//update the list of elements in the GUI
						GUIview.instance.addToElemtList(nodesList.get(i));  
					  } 
				  }
				  //if there has not a value
				  else{
					//update the list of elements in the GUI
					  GUIview.instance.addToElemtList(nodesList.get(i));
				  }
				  
				  //promote i - the index that running on nodesList (list of string of the elements) 
				  i++;
			  }//end if
		  }	//end for		  
	}
	
	
	public static void findTheNode(String node){
		String temp, withoutNumberNode = null;
		int num = 1;
		boolean goOn = true;
		
		//System.out.println("in findTheNode");
		NodeList nodeLst = currentNode.getChildNodes();
		//System.out.println("nodeLst: " + nodeLst.getLength());
		
		//update the value/name text
		//GUIview.instance.setNameValueText(node);
		
		if(node.contains("=")){
			System.out.println("the node contain = ");
			int idx = node.indexOf('=');
			withoutNumberNode = node.substring(0, idx-1);
		}
		//check if it is numbered
		else if(node.endsWith("]")){
			int lenght = node.length();
			//get the number
			temp = (String) node.subSequence(lenght-2, lenght-1);
			//System.out.println("temp :" + temp);
			//convert to int
			num = Integer.parseInt(temp);
			//the name without [x] 
			withoutNumberNode = (String) node.subSequence(0, lenght-3);
			
			
		}
		else{
			withoutNumberNode = node;
		}
		
		//System.out.println("withoutNumberNode: " + withoutNumberNode);
		//System.out.println("currentNode: " + currentNode.getNodeName());
		  for (int s = 0; s < nodeLst.getLength()&&goOn; s++) {
			  
			  Node fstNode = nodeLst.item(s);
			  //check if it is element
			  if (fstNode.getNodeType() == Node.ELEMENT_NODE){
				  //System.out.println("in for");
				  //System.out.println("Name: " + fstNode.getNodeName()); 
				  //if the name found
				  if(fstNode.getNodeName().equals(withoutNumberNode)){
					  //in this case the node found
					  if(num == 1){
						  //update the count
						  count++;
						  //enable the button back
						  GUIview.instance.enableButtonBack();
						  System.out.println("in the if num==1");
						  System.out.println("fstNode name: " + fstNode.getNodeName());
						  readChildrens(fstNode);
						  goOn = false;
					  }
					  num--;
				  }
				  
			  }
		  }	//end for			
	}
	
	/*
	 * the function is back to the parebt node
	 */
	public void back (){
		//if the current node is not a null
		System.out.println("in back func");
		System.out.println("count: " + count);
		if(count>0){
			count--;
			//if count==0 disable the button back
			if(count == 0){
				  //disable the button back
				  GUIview.instance.disableButtonBack();
			}
			//go to the parent of the current node
			Node node = currentNode.getParentNode();
				  
			//update the Relative Expression
			GUIview.instance.backRelativeExpression();
			
			//update the value/name text
			//GUIview.instance.setNameValueText(node.getNodeName());
			//read and display the childrens of this node
			readChildrens(node);			
			
		}
	}
	
	/*
	 * the function get currentPath and return nodes
	 * ListOfNodes - to contain the same elements type in the algoritem
	 * ListOfNodes2 - save in the prime loop the same elements and in the end transfer to ListOfNodes
	 */
	public void openCurrentPath (String currentPath){
		
		ArrayList<Node> ListOfNodes, ListOfNodes2;		
		int exist=0, countE, numOfElements, lenght;
		ListOfNodes = new ArrayList<Node>();
		ListOfNodes2 = new ArrayList<Node>();
		//ArrayList<String> nodeList = new ArrayList<String>();
		//System.out.println("in openCurrentPath");
		//check if the expression start with '/'
		if(!currentPath.startsWith("/")){
			GUIview.instance.updateComments("The expression is not a legal");
			GUIview.instance.updateCurrentPath(GUIview.instance.getStringCurrentPath());
		}
		else{
			//get the elements		
			String [] tmpList = currentPath.split("/");
			ArrayList<String> nodeList = new ArrayList<String>();
			
			//move the tmpList string to nodeList without 
			for(int i=0; i<tmpList.length; i++){
				if(tmpList[i].equals("")){
					//do nothing
				}
				else{
					nodeList.add(tmpList[i]);
				}
			}			
			for(int i=0; i<nodeList.size(); i++){
				System.out.println("name: " + nodeList.get(i));
			}
			//int numElem = nodeList.length-1;

			//run check for the elements
			Node node = rootNode;

			//check if the root is ok
			if(node.getNodeName().equals(nodeList.get(0))){
				//for start there is just one element - the root
				numOfElements = 1;
				ListOfNodes.add(node);				
				//go over the all elements that was in the current Path
				for(int i=1; i<nodeList.size(); i++){
					//initialize countE & exist
					countE = 0;
					exist = 0;
					//empty the ListOfNodes2
					lenght = ListOfNodes2.size();
					for(int k=0; k<lenght; k++){
						ListOfNodes2.remove(0);
					}
					/*
					//System.out.println("ListOfNodes2 lenght: " + ListOfNodes2.size()); 
					//System.out.println("*******go over the ListOfNodes before the nodes are taken from there**************");
					for(int k=0; k<ListOfNodes.size(); k++){
						System.out.println(ListOfNodes.get(k).getNodeName());
					}
					//System.out.println("******##################################**************");
					//System.out.println("*******go over the ListOfNodes2**************");
					for(int k=0; k<ListOfNodes2.size(); k++){
						System.out.println(ListOfNodes2.get(k).getNodeName());
					}
					System.out.println("******##################################**************");
					*/
					// go over the all elements in the ListOfNodes - there is have the same type of elements
					for(int j=0; j<numOfElements; j++){
						//get the childrens of the node j in ListOfNodes
						NodeList nodeLst = ListOfNodes.get(j).getChildNodes();
						
						//go over the childrens of the element
						  for (int s = 0; s < nodeLst.getLength(); s++) {							  
							  Node fstNode = nodeLst.item(s);
							  //check if it is element
							  if (fstNode.getNodeType() == Node.ELEMENT_NODE){								  
								  //System.out.println("Name: " + fstNode.getNodeName()); 
								  //in this case the node found
								  if(fstNode.getNodeName().equals(nodeList.get(i))){									  
									  exist = 1;
									  //System.out.println("in the if"); 									  
									  //save the node in  ListOfNodes2 & promote countE
									  ListOfNodes2.add(fstNode);
									  countE++;
								  }								  
							  }
						  }	
					}//end of second for
					
					numOfElements = countE;
					//empty list ListOfNodes and take all the nodes from ListOfNodes2
					lenght = ListOfNodes.size();
					for(int k=0; k<lenght; k++){
						ListOfNodes.remove(0);
					}					
					for(int k=0; k<ListOfNodes2.size(); k++){
						ListOfNodes.add(ListOfNodes2.get(k));						
					}
					
					//if the element was not found
					if(exist == 0){
						GUIview.instance.updateComments("The element " + nodeList.get(i) +" does not exist");
					}
					
				}//end of the prime for
				
				//if the path is exist
				if(exist == 1){
					//System.out.println("ListOfNodes-lenght: " + ListOfNodes.size());
					//send the nodes to the GUI
					GUIview.instance.updateButtons(ListOfNodes);
				}
				
			}//end of the if root is valid
			else{
				GUIview.instance.updateComments("The element " + nodeList.get(0) +" does not exist");
				GUIview.instance.updateCurrentPath(GUIview.instance.getStringCurrentPath());
			}			
		}//end else
	}
	//end of openCurrentPath
	
	/*
	public void openButton(Node node){
		
		
	}
	*/
		public static void orderList(ArrayList<String> arrList){
			String temp, temp3;
			char[] temp2 = new char[40];
			//go over the list
			for(int i=0; i<arrList.size(); i++){
				boolean goOn = true;
				//check the previus nodes
				for(int j=i; j>0&goOn; j--){
					temp = arrList.get(j-1);
					//if j-1 word with number remove the number
					if(arrList.get(j-1).endsWith("]")){
						//System.out.println("in if ");
						//System.out.println(arrList.get(0) +"   " + arrList.get(1)  +"   "  + arrList.get(2));
						int lenght = arrList.get(j-1).length();					
						temp3 = (String) temp.subSequence(0, lenght-3);
						//System.out.println("temp3 without [x]:" + temp3);
						temp = temp3;						
					}
					
					//check if the same words
					if(arrList.get(i).equals(temp)){
						//check if this word all ready checked with number
						goOn = false;						
						//if it is already numbered
						if(arrList.get(j-1).endsWith("]")){
							//System.out.println("in if ");
							//System.out.println(arrList.get(0) +"   " + arrList.get(1)  +"   "  + arrList.get(2));
							int lenght = arrList.get(j-1).length();
							//get the number
							temp3 = (String) arrList.get(j-1).subSequence(lenght-2, lenght-1);
							//System.out.println("temp3 :" + temp3);
							//convert to int
							int num = Integer.parseInt(temp3);
							num++;
							//add the new number to the i elemnt
							temp = arrList.get(i);
							arrList.set(i, temp+"["+num+"]");
							//System.out.println(" arrList.get(i): " + arrList.get(i));
						}
						//if it was not numbered
						else{
							//System.out.println("in else");
							//number it 
							temp = arrList.get(j-1);
							arrList.set(j-1, temp+"[1]");
							//System.out.println("temp :" + temp);
							temp = arrList.get(i);
							arrList.set(i, temp+"[2]");
							//System.out.println("temp :" + temp);							
						}
					}//end prime if
				}
			}//end prime for
			
		}
}